package api

import (
	"buding-ai/internal/core"
	"buding-ai/internal/repository"
	"buding-ai/internal/repository/model"
	"buding-ai/internal/service"
	"buding-ai/internal/web/dto"
	"buding-ai/internal/web/response"
	"buding-ai/pkg/mcpTool"
	"buding-ai/pkg/openapi"
	"buding-ai/pkg/utils/jwt"
	"buding-ai/pkg/vec"
	"context"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"github.com/sashabaranov/go-openai"
	"io"
	"log"
	"strings"
	"sync/atomic"
)

const (
	ErrorEvent     = "error"
	ConnectedEvent = "connected"
	StartEvent     = "start"
	KnowledgeEvent = "knowledge"
	ChunkEvent     = "chunk"
	ReasonEvent    = "reason"
	DoneEvent      = "done"
)

type SSEEvent struct {
	Event string      `json:"event"`
	Data  interface{} `json:"data"`
}

type sseChan chan SSEEvent

func (c sseChan) sseError(msg string) {
	c <- SSEEvent{
		Event: ErrorEvent,
		Data:  gin.H{"error": msg},
	}
}

func (c sseChan) sseConnected(id uint, msg, model string) {
	c <- SSEEvent{
		Event: ConnectedEvent,
		Data: gin.H{
			"message":     "SSE连接已建立，开始处理问题",
			"chatId":      id,
			"userMessage": msg,
			"model":       model,
		},
	}
}

func (c sseChan) sseStart(model string) {
	c <- SSEEvent{
		Event: StartEvent,
		Data: gin.H{
			"message": "开始生成回复",
			"model":   model,
		},
	}
}

func (c sseChan) sseKnowledge(knowledgeContent string) {
	c <- SSEEvent{
		Event: KnowledgeEvent,
		Data:  gin.H{"content": knowledgeContent},
	}
}

func (c sseChan) sseChunk(content string) {
	c <- SSEEvent{
		Event: ChunkEvent,
		Data:  content,
	}
}

func (c sseChan) sseReason(content string) {
	c <- SSEEvent{
		Event: ReasonEvent,
		Data:  content,
	}
}

func (c sseChan) sseDone(content, reason, model string) {
	c <- SSEEvent{
		Event: DoneEvent,
		Data: gin.H{
			"message":      "回复生成完成",
			"fullResponse": content,
			"fullReason":   reason,
			"model":        model,
		},
	}
}

func (c sseChan) close() {
	close(c)
}

type ChatApi struct {
	group            *gin.RouterGroup
	agentRoleService *service.AgentRoleService
	modelSrv         *service.AgentModelProviderService
	BaseApi
}

func NewChat(group *gin.RouterGroup) *ChatApi {
	chat := &ChatApi{
		group:            group,
		agentRoleService: service.NewAgentRoleService(),
		modelSrv:         service.NewAgentModelProviderService(),
	}
	group.POST("/add", chat.Add)
	group.GET("/list", chat.List)
	group.DELETE("/:id", chat.DeleteChat)
	group.GET("/question/list", chat.QuestionList)
	group.POST("/question", chat.Question)
	group.GET("/model/list", chat.ModelList)
	group.GET("/roleList", chat.RoleList)

	return chat
}

func (api *ChatApi) RoleList(ctx *gin.Context) {
	list, err := api.agentRoleService.List()
	if err != nil {
		response.InternalError(ctx, "获取列表失败", err)
		return
	}
	var result []response.ChatAgentRole
	copier.Copy(&result, &list)
	response.SuccessWithData(ctx, result)
}

func (api *ChatApi) ModelList(ctx *gin.Context) {
	// 获取模型列表
	var err error
	var list []model.AgentModelProvider
	list, err = api.modelSrv.GetList()
	if err != nil {
		response.InternalError(ctx, "获取模型列表失败", err)
		return
	}
	var result []response.ChatAgentModelVO
	for _, provider := range list {
		result = append(result, response.ChatAgentModelVO{
			ID:          provider.ID,
			Name:        provider.Name,
			Logo:        provider.Logo,
			Description: provider.Description,
			Models:      strings.Split(provider.AiModel, ","),
		})
	}

	// 返回响应
	response.SuccessWithData(ctx, result)
}

// Add 开启新对话
func (api *ChatApi) Add(ctx *gin.Context) {
	var err error
	var create dto.ChatCreateDTO
	var chat *model.Chat
	var user *jwt.Claims
	user, err = api.CurrentUser(ctx)
	if err != nil {
		log.Println("获取用户信息失败", err.Error())
	}
	if err = ctx.ShouldBindBodyWithJSON(&create); err != nil {
		response.ParamBindError(ctx, err)
		return
	}
	// 添加一个会话
	chat, err = repository.GetChatRepository().InitChat(user.UserID, create.Name)
	if err != nil {
		response.InternalError(ctx, "创建新的聊天失败", err)
	}
	// 如果SystemFlag=1，则添加系统消息到MongoDB
	if create.SystemFlag != 0 && create.SystemContext != "" {
		// 插入到MongoDB
		if _, err := repository.GetMessageRepository().Create(int64(chat.ID), 1, openapi.SYSTEM, create.SystemContext, true); err != nil {
			response.InternalError(ctx, "创建系统消息失败", err)
			return
		}
		chat.MessageCount = 1
	}
	//返回结果
	response.SuccessWithData(ctx, chat.ID)
}

// Question 对话
func (api *ChatApi) Question(ctx *gin.Context) {
	// 1. 参数验证
	var quest dto.ChatQuestionDTO
	if err := ctx.ShouldBindBodyWithJSON(&quest); err != nil {
		response.ParamBindError(ctx, err)
		return
	}

	// 2. 获取对话
	var chat model.Chat
	if err := core.DB.First(&chat, quest.Id).Error; err != nil {
		response.InternalError(ctx, "获取对话失败", err)
		return
	}

	// 3. 获取历史消息
	historicalMsgs, err := repository.GetMessageRepository().GetAllMessagesByChatId(chat.ID, true)
	if err != nil {
		response.InternalError(ctx, "获取历史消息失败", err)
		return
	}

	// 4. 计算下一个序号
	nextSeq := 1
	if len(historicalMsgs) > 0 {
		nextSeq = len(historicalMsgs) + 1
	}

	// 5. 存储用户问题
	var userMsg *model.Message
	if userMsg, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.USER, quest.Message, false); err != nil {
		response.InternalError(ctx, "保存用户消息失败", err)
		return
	}
	historicalMsgs = append(historicalMsgs, userMsg)
	nextSeq++

	// 6. RAG 知识库检索
	embedding, err := vec.GetTongYiEmbedding(quest.Message)
	if err != nil {
		response.InternalError(ctx, "问题获取向量失败", err)
		return
	}

	// 7. 搜索相关问答
	points, err := vec.Client.SearchPoints("knowledge", embedding, 10, 0.9)
	if err != nil {
		response.InternalError(ctx, "获取知识库失败", err)
		return
	}

	// 8. 存储知识库聊天记录
	if len(points) > 0 {
		var knowledgeBuilder strings.Builder
		knowledgeBuilder.WriteString("知识库内容：\n")
		for _, point := range points {
			question := point.Payload["question"].GetStringValue()
			answer := point.Payload["answer"].GetStringValue()
			knowledgeBuilder.WriteString(fmt.Sprintf("问题：%s 答案：%s\n", question, answer))
		}

		var rag *model.Message
		if rag, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.SYSTEM, knowledgeBuilder.String(), true); err != nil {
			response.InternalError(ctx, "保存RAG消息失败", err)
			return
		}
		historicalMsgs = append(historicalMsgs, rag)
		nextSeq++
	}

	// 9. 构造消息列表用于AI请求
	messages := make([]openai.ChatCompletionMessage, 0, len(historicalMsgs))
	for _, msg := range historicalMsgs {
		messages = append(messages, openai.ChatCompletionMessage{
			Role:    msg.Role,
			Content: msg.Content,
		})
	}

	// 10. 调用AI接口
	model := "deepseek-chat"
	if quest.Model != "" {
		model = quest.Model
	}

	responseText, err := openapi.Chat("https://api.deepseek.com/v1", model,
		"sk-a12fcd16ec2849af95e0a34f2235d7ea", messages)
	if err != nil {
		response.InternalError(ctx, "调用AI接口失败", err)
		return
	}

	// 11. 保存AI回复
	if _, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.ASSISTANT, responseText, false); err != nil {
		log.Printf("保存AI回复失败: %v", err)
	}

	// 12. 更新消息数量
	chat.MessageCount = nextSeq
	if err := core.DB.Model(&chat).Update("message_count", nextSeq).Error; err != nil {
		log.Printf("更新消息数量失败: %v", err)
	}

	// 13. 返回结果
	response.Success(ctx, "响应成功", gin.H{
		"response": responseText,
	})
}

// QuestionSSEStream 建立SSE连接并流式返回响应
func (api *ChatApi) QuestionSSEStream(ctx *gin.Context) {
	// 保持连接
	api.keepAlive(ctx)
	eventChan := make(sseChan, 1024)
	var stop atomic.Bool
	stop.Store(false)
	go func() {
		api.doQuestion(ctx, eventChan, &stop)
	}()

	ctx.Stream(func(_ io.Writer) bool {
		if event, ok := <-eventChan; ok {
			if data, ok := event.Data.(string); ok {
				event.Data = strings.ReplaceAll(data, "\r", ``)
			}
			ctx.SSEvent(event.Event, event.Data)
			return true
		}
		return false
	})

	log.Println("连接中断")
	stop.Store(true)
	for range eventChan {
	}
}
func (api *ChatApi) doQuestion(ctx *gin.Context, eventChan sseChan, stop *atomic.Bool) {
	defer eventChan.close()
	query, err := api.buildSseMessage(ctx)
	if err != nil {
		eventChan.sseError(err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}
	// 发送连接成功事件
	eventChan.sseConnected(query.Id, query.Message, query.Model)

	// 1. 获取聊天记录
	var chat model.Chat
	if err := core.DB.First(&chat, query.Id).Error; err != nil {
		eventChan.sseError("获取聊天记录失败: " + err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}
	// 2. 获取历史消息
	historicalMsgs, err := repository.GetMessageRepository().GetAllMessagesByChatId(chat.ID, true)
	if err != nil {
		eventChan.sseError("获取历史消息失败: " + err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}
	// 4. 存储用户问题
	nextSeq := 1
	if len(historicalMsgs) > 0 {
		nextSeq = len(historicalMsgs) + 1
	}
	var userMsg *model.Message
	if userMsg, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.USER, query.Message, false); err != nil {
		eventChan.sseError("保存用户消息失败:" + err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}
	historicalMsgs = append(historicalMsgs, userMsg)
	nextSeq++

	// 5. RAG 知识库检索
	embedding, err := vec.GetTongYiEmbedding(query.Message)
	if err != nil {
		eventChan.sseError("问题获取向量失败: " + err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}

	// 6. 搜索相关问答
	points, err := vec.Client.SearchPoints("knowledge", embedding, 10, 0.9)
	if err != nil {
		eventChan.sseError("获取知识库失败: " + err.Error())
		log.Printf("出现异常，连接中断:%s", err.Error())
		return
	}

	// 7. 存储知识库聊天记录
	var knowledgeContent string
	if len(points) > 0 {
		var knowledgeBuilder strings.Builder
		knowledgeBuilder.WriteString("知识库内容：\n")
		for _, point := range points {
			question := point.Payload["question"].GetStringValue()
			answer := point.Payload["answer"].GetStringValue()
			knowledgeBuilder.WriteString(fmt.Sprintf("问题：%s 答案：%s\n", question, answer))
		}
		knowledgeContent = knowledgeBuilder.String()

		var rag *model.Message
		if rag, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.SYSTEM, knowledgeContent, true); err != nil {
			log.Printf("保存RAG消息失败: %v", err)
		} else {
			historicalMsgs = append(historicalMsgs, rag)
			nextSeq++
		}
		// 发送知识库匹配事件
		eventChan.sseKnowledge(knowledgeContent)
	}

	// 8. 构造消息列表用于AI请求
	messages := make([]openai.ChatCompletionMessage, 0, len(historicalMsgs))
	for _, msg := range historicalMsgs {
		messages = append(messages, openai.ChatCompletionMessage{
			Role:    msg.Role,
			Content: msg.Content,
		})
	}

	// 10. 发送开始事件
	eventChan.sseStart(query.Model)

	modelProviderMap, err := api.modelSrv.GetClientList()
	if err != nil {
		eventChan.sseError("获取大模型连接失败" + err.Error())
		return
	}
	modelProvider := modelProviderMap[query.Agent]
	// 11. 流式处理AI响应
	fullResponse := ""
	fullReasonContent := ""
	tool := api.buildTool()
	tools := tool.AllTools()
	log.Println("加载到工具:", len(tools))
	defer tool.Close()
	for {
		stream, err := openapi.ChatStreamWithTool(context.Background(), modelProvider.Client, query.Model, messages,
			tools, modelProvider.Cfg.Temperature, modelProvider.Cfg.MaxTokens)
		if err != nil {
			eventChan.sseError("发起大模型请求失败:" + err.Error())
			log.Printf("出现异常，连接中断:%s", err.Error())
			return
		}
		defer stream.Close()
		calls := make([]openai.ToolCall, 0)
	loop:
		for {
			if stop.Load() {
				log.Println("检测到sse流已关闭,停止生成！！！")
				return
			}
			completion, err := stream.Recv()
			if err != nil {
				// 如果是因为流结束而退出，则正常处理
				if strings.Contains(err.Error(), "EOF") {
					stream.Close()
					log.Printf("正常中断")
					break loop
				}
				// 其他错误则发送错误事件
				eventChan.sseError("接收流式响应失败: " + err.Error())
				log.Printf("出现异常，连接中断:%s", err.Error())
				return
			}
			// 响应回答
			content := completion.Choices[0].Delta.Content
			if content != "" && content != "ping" {
				eventChan.sseChunk(content)
				fullResponse += content
			}

			reasonContent := completion.Choices[0].Delta.ReasoningContent
			if reasonContent != "" {
				eventChan.sseReason(reasonContent)
				fullReasonContent += reasonContent
			}
			//处理tool
			if len(completion.Choices[0].Delta.ToolCalls) > 0 {
				for _, value := range completion.Choices[0].Delta.ToolCalls {
					if value.Index == nil {
						index := 0
						value.Index = &index
					}
					index := value.Index
					if len(calls) < *index+1 {
						calls = append(calls, value)
						continue
					}
					call := calls[*index]
					call.Function.Name = call.Function.Name + value.Function.Name
					call.Function.Arguments = call.Function.Arguments + value.Function.Arguments
					calls[*index] = call
				}
			}
		}
		if len(calls) == 0 {
			break
		}
		log.Println("本次会话加载工具数量：", len(calls))
		//执行call
		for _, call := range calls {
			log.Printf("执行工具:%s %s \n", call.Function.Name, call.Function.Arguments)
			result, err := tool.Call(call.Function.Name, call.Function.Arguments)
			messages = append(messages, openai.ChatCompletionMessage{
				Role: openapi.ASSISTANT,
				ToolCalls: []openai.ToolCall{
					call,
				},
				ToolCallID: call.ID,
			})
			if err != nil {
				log.Println("执行出错", err.Error())
				result = "tool call failed"
			}
			log.Printf("工具{%s}执行结果:%s\n", call.Function.Name, result)
			messages = append(messages, openai.ChatCompletionMessage{
				Role:       openapi.TOOL,
				Content:    result,
				ToolCallID: call.ID,
			})
		}
	}

	// 12. 保存AI完整回复
	if fullResponse != "" {
		if _, err = repository.GetMessageRepository().Create(int64(chat.ID), nextSeq, openapi.ASSISTANT, fullResponse, false); err != nil {
			log.Printf("保存AI回复失败: %v", err)
		}
		// 13. 更新消息数量
		chat.MessageCount = nextSeq
		if err := core.DB.Model(&chat).Update("message_count", nextSeq).Error; err != nil {
			log.Printf("更新消息数量失败: %v", err)
		}
	}
	// 14. 发送完成事件
	eventChan.sseDone(fullResponse, fullReasonContent, query.Model)
}

func (api *ChatApi) keepAlive(ctx *gin.Context) {
	_ = ctx.Request.ParseMultipartForm(32 << 20)
	// 设置SSE头信息
	ctx.Header("Content-Type", "text/event-stream")
	ctx.Header("Cache-Control", "no-cache")
	ctx.Header("Connection", "keep-alive")
	ctx.Header("Transfer-Encoding", "chunked")
	ctx.Header("X-Accel-Buffering", "no")
	ctx.Header(`Access-Control-Allow-Origin`, `*`)
}

func (api *ChatApi) buildTool() mcpTool.McpClientList {
	tools, err := repository.GetMcpRepository().GetTools()
	if err != nil {
		return nil
	}
	//转换成mcp的服务
	return mcpTool.ConvertMCPToolsToOpenAI(tools)
}

func (api *ChatApi) buildSseMessage(ctx *gin.Context) (*dto.ChatQuestionDTO, error) {
	var query dto.ChatQuestionDTO
	if err := ctx.ShouldBindQuery(&query); err != nil {
		return nil, errors.New("获取绑定参数失败")
	}
	if query.Message == "" {
		return nil, errors.New("请输入消息")
	}
	return &query, nil
}

// List 获取会话列表
func (api *ChatApi) List(ctx *gin.Context) {
	var user *jwt.Claims
	var err error
	user, err = api.CurrentUser(ctx)
	if err != nil {
		log.Println("获取用户信息失败", err.Error())
	}
	var chats []model.Chat
	core.DB.Order("updated_at desc").Where("is_hide=? and user_id=?", 0, user.UserID).Find(&chats)
	response.SuccessWithData(ctx, chats)
}

func (api *ChatApi) QuestionList(ctx *gin.Context) {
	// 转换聊天ID为整数
	chatId, err := api.GetQueryUint(ctx, "id")
	if err != nil {
		response.ParamError(ctx, "无效的聊天ID: "+err.Error())
		return
	}

	// 从MongoDB获取该聊天的所有消息
	messages, err := repository.GetMessageRepository().GetMessagesByChatIdInt64(int64(chatId), 0, 0, false)
	if err != nil {
		response.InternalError(ctx, "获取聊天消息失败", err)
		return
	}

	// 筛选出用户问题(role为user的消息)
	var questions []response.ChatQuestionVO
	for _, msg := range messages {
		questions = append(questions, response.ChatQuestionVO{
			Role:      msg.Role,
			Content:   msg.Content,
			Timestamp: msg.Timestamp,
		})
	}

	// 返回结果
	response.SuccessWithData(ctx, questions)
}

// DeleteChat 删除聊天记录
func (api *ChatApi) DeleteChat(ctx *gin.Context) {
	// 1. 参数验证
	id, err := api.GetParamUint(ctx, "id")
	if err != nil {
		response.ParamError(ctx, "聊天ID不能为空")
		return
	}
	if id == 0 {
		response.ParamError(ctx, "聊天id不能为0")
		return
	}
	// 2. 查询聊天记录是否存在
	var chat model.Chat
	if err := core.DB.First(&chat, id).Error; err != nil {
		response.InternalError(ctx, "获取聊天记录失败", err)
		return
	}

	// 3. 逻辑删除聊天记录（修改is_hide字段为1）
	if err := core.DB.Delete(&chat).Error; err != nil {
		response.InternalError(ctx, "删除聊天记录失败", err)
		return
	}

	response.Success(ctx, "删除聊天记录成功", nil)
}
